package olegroshka.src.com.bofa.olegroshka.datasource;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import olegroshka.src.com.bofa.olegroshka.filter.Filter;

public class FlatFileDataSource implements DataSource<String[]> {

	private final String delimiter; 
	private final String filePath; 
	private BufferedReader br;
	private final Filter<String[]> filter;
	private boolean eof = false;
	
	public FlatFileDataSource(
			String filePath, 
			String delimiter) {
		this(filePath, delimiter, null);
	}
	
	
	public FlatFileDataSource(
			String filePath, 
			String delimiter, 
			Filter<String[]> filter) {
		this.delimiter = delimiter;
		this.filePath = filePath;
		this.filter = filter;
	}

	public Iterator<String[]> iterator() {
		if( br == null ) {
			throw new IllegalStateException("Method begin() has not been invoked.");
		}
		return new Iterator<String[]>() {
			private String[] cursor = null;
			 
			public boolean hasNext() {
				String[] current = cursor;
				if( current == null ) {
					cursor = next();
				}
				return !eof;
			}

			public String[] next() {
				String[] current = cursor;
				if( current != null ) {
					cursor = null;
					return current;
				} 
				String[] row =  null;
				List<String> tokens = null;
				try {
					for ( String line = readNextLine(); line != null; line = readNextLine() ) {
						tokens = new ArrayList<String>(3);
						StringTokenizer st = new StringTokenizer(line, delimiter);
						while ( st.hasMoreTokens() ) {
							String token = st.nextToken();
							tokens.add(token);
						}
						row = new String[tokens.size()];
						tokens.toArray(row);
						if( filter == null || filter.accept(row) ) {
							break;
						}
					}
					if( row == null ) {
						eof = true;
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				return row;
			}

			public void remove() {
				throw new UnsupportedOperationException();
			}
		};
	}

	private String readNextLine() throws IOException {
		return br.readLine();
	}
	
	public void begin() {
		try {
			this.br = new BufferedReader(new FileReader(filePath));
		} catch (FileNotFoundException e) {
			new IllegalStateException("Can't read from file: " + filePath, e);
		}
	}

	public void end() {
		try {
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
